package mua.core.interpreter;

import mua.core.operation.MuaOperation;
import mua.core.value.Number;
import mua.core.value.*;

import java.util.ArrayList;
import java.util.Stack;
import java.util.regex.Pattern;
/**
 * @date 2020年11月5日15点40分
 * @author 帆
 * 工具类，包含了许多地方公用的函数
 */
public class Util {
    /**
     * match the number type.
     */
    private static Pattern NUMBER_PATTERN = Pattern.compile("-?[0-9]+.?[0-9]*");

    /**
     * @param str String
     * @return is number or not
     */
    public static boolean isNumber(String str){
        return NUMBER_PATTERN.matcher(str).matches();
    }

    /**
     * 判断条件:
     * 1.含有"return"或"export"；或
     * （ 1.仅有两对连续的"[]"；且
     *    2.第一对"[]"中不能有"[]"）
     * @param s 该字符串
     * @return 是否为函数体
     */
    public static boolean isFunction(String s) {
        // 1.仅有两对连续的"[]"
        // 2.第一对"[]"中不能有"[]"
        //排除仅为"["
        if(s.length()<=2)return false;
        //去掉"[]"
        String substring = myTrim(s.substring(1,s.length()-1));
        //判断仅为两对连续的"[]"，且第一对中不能有"[]"
        if(substring.charAt(0)!='[') return false;
        int bracketCount = 0;
        Stack<Boolean> bracket = new Stack<>();
        for(int i=0;i<substring.length();i++){
            if(substring.charAt(i)=='['){
                //第一对"[]"有"["
                if(!bracket.isEmpty()&&bracketCount==0)return false;
                else bracket.push(true);
            }
            else if(substring.charAt(i)==']'){
                bracket.pop();
                //如果弹出后为空栈，证明已经计算一对"[]"
                //一共需要两对
                if(bracket.isEmpty()){
                    bracketCount++;
                    //如果计数为2，且i不为最后一个字符，则返回false
                    if(bracketCount==2&&i+1<substring.length())
                        return false;
                }
            }
        }
        //如果不为括号对数不为2
        return bracketCount == 2;
    }

    /**
     * 判断s是否为操作表达式
     * 目前简单认为同时满足以下两个条件即为表达式
     * 1. isFunction(s)为false
     * 2. 含有operation
     * @param s 被"[]"包含的字符串，包括"[]"
     * @return 如果为操作表达式，则返回true
     */
    public static boolean isExpression(String s, FunctionBody functionBody) {
        //排除"["
        if(s.length()<=2)return false;
        //去掉"[]"
        String substring = myTrim(s.substring(1,s.length()-1));
        //判断是否有操作符
        String[] parts = substring.split(" ");
        //第一部分不为空，且为操作符
        return !parts[0].isEmpty() && MuaOperation.contains(parts[0], functionBody);
    }

    /**
     * 判断类型
     * @param str 字符串
     * @return 返回对应类型
     */
    public static MuaValue judgeType(String str, FunctionBody functionBody){
        MuaValue value;
        if(str==null){
            return new MuaValue();
        }
        //数字类型
        if(isNumber(str)){
            value = new Number(str);
        }
        //布尔型
        else if("true".equals(str)){
            value = new Bool("true");
        }else if("false".equals(str)){
            value = new Bool("false");
        }
        //算术表达式
        else if(str.charAt(0)=='('){
            return ArithmeticExpression.parseExpression(str, functionBody);
        }
        else if(str.charAt(0)=='['){
            if(isFunction(str)){
                return new FunctionBody(str,functionBody);
            }else{
                return new List(str);
            }
        }
        //字
        else {
            value = new Word(str);
        }
        return value;
    }

    /**
     * 判断类型
     * @param str 字符串
     * @return 返回对应类型
     */
    public static MuaValue judgeType(String str){
        MuaValue value;
        if(str==null){
            return new MuaValue();
        }
        //数字类型
        if(isNumber(str)){
            value = new Number(str);
        }
        //布尔型
        else if("true".equals(str)){
            value = new Bool("true");
        }else if("false".equals(str)){
            value = new Bool("false");
        }
        else if(str.charAt(0)=='['){
            return new List(str);
        }
        //字
        else {
            value = new Word(str);
        }
        return value;
    }

    /**
     * 将String以第一个空格或者"()"或者"[]"分成两部分
     * @param ops 系列操作字符串
     * @return 返回第一部分和剩余部分，如果剩余部分为空则设第二部分为null
     */
    public static String[] split(String ops) {
        if(ops==null){
            return new String[]{null,null};
        }else if(ops.isEmpty()){
            return new String[]{null,null};
        }
        ops = myTrim(ops);
        //如果第一部分是表达式
        if (ops.charAt(0)=='('){
            //用来存放小括号，来判断第一部分的括号包裹的内容
            Stack<Boolean> brackets = new Stack<>();
            int rightIndex = 0;
            while(rightIndex<ops.length()){
                if(ops.charAt(rightIndex)==')'){
                    brackets.pop();
                    if(brackets.isEmpty())break;
                }else if(ops.charAt(rightIndex)=='('){
                    brackets.push(true);
                }
                rightIndex++;
            }
            return new String[]{ops.substring(0,rightIndex+1),ops.substring(rightIndex+1)};
        }
        //如果第一部分是列表
        if (ops.charAt(0)=='['){
            //用来存放中括号，来判断第一部分的括号包裹的内容
            Stack<Boolean> brackets = new Stack<>();
            int rightIndex = 0;
            while(rightIndex<ops.length()){
                if(ops.charAt(rightIndex)==']'){
                    brackets.pop();
                    if(brackets.isEmpty())break;
                }else if(ops.charAt(rightIndex)=='['){
                    brackets.push(true);
                }
                rightIndex++;
            }
            return new String[]{ops.substring(0,rightIndex+1),ops.substring(rightIndex+1)};
        }
        //如果第一项非表达式或列表
        int index = ops.indexOf(' ');
        if(index==-1){
            return new String[]{ops,null};
        } else{
            return new String[]{ops.substring(0,index),ops.substring(index+1)};
        }
    }

    /**
     * 用于计算在当前操作符下，操作数的个数是否够用
     * @param pop 弹出的操作符
     * @return 返回是否够用，不够用则false
     */
    public static int numOfPara(String pop, FunctionBody functionBody) {
        switch (pop){
            case "print":
            case "thing":
            case "not":
            case "erase":
            case "isbool":
            case "isempty":
            case "isname":
            case "islist":
            case "isnumber":
            case "isword":
            case "run":
            case "export":
            case "return":
            case "readlist":
            case "first":
            case "last":
            case "butfirst":
            case "butlast":
            case "random":
            case "int":
            case "sqrt":
            case "save":
            case "load":
                return 1;
            case "make":
            case "eq":
            case "gt":
            case "lt":
            case "or":
            case "add":
            case "and":
            case "div":
            case "mod":
            case "mul":
            case "sub":
            case "word":
            case "sentence":
            case "list":
            case "join":
                return 2;
            case "if":
                return 3;
            default:
                if(functionBody!=null){
                    if(functionBody.getLocalVariable().get(pop)!=null)
                    return ((FunctionBody)(functionBody.getLocalVariable().get(pop))).getArguments().size();
                }
                return ((FunctionBody)(Global.globalVariable.get(pop))).getArguments().size();
        }
    }

    /**
     * 判断是否为完整的一句话
     * 用于run <expression>和函数中
     * @param operations 操作栈
     * @param values 变量的个数
     * @return 返回是否为完整的一句话
     */
    public static boolean isOneSentence(Stack<String> operations, int values, FunctionBody functionBody) {
        Stack<String> tempOperation;
        boolean flag = true;
        //用来尝试是否为完整一句话进行复制操作栈
        tempOperation =(Stack<String>)operations.clone();
        while(!tempOperation.empty()){
            //根据操作符减去value的个数，并加上1，如果不行则break
            if((values-=(numOfPara(tempOperation.pop(), functionBody)-1))<=0){
                flag=false;
                break;
            }
        }
        return flag;
    }

    /**
     * 将所有tab转为空格，并去掉首尾的空格
     * @param line 输入的string
     * @return 返回trim后的字符串
     */
    public static String myTrim(String line) {
        StringBuilder ret = new StringBuilder(line);

        for(int i=0;i<ret.length();i++){
            if(ret.charAt(i)=='\t')ret.replace(i,i+1," ");
        }
        return ret.toString().trim();
    }

    /**
     * 返回一个分割，每项为空格分隔或"()","[]"分隔
     * @param s 字符串
     * @return 返回分隔的各个部分
     */
    public static ArrayList<String> mySplit(String s) {
        ArrayList<String> ret = new ArrayList<>();
        StringBuilder temp = new StringBuilder(myTrim(s));
        int endIndex;
        //记录括号
        Stack<Boolean> bracket = new Stack<>();
        //当temp长度大于0的时候
        while(temp.length()>0){
            //中括号包含
            if(temp.charAt(0)=='['){
                for(int i=0;i<temp.length();i++){
                    if(temp.charAt(i)=='['){
                        bracket.push(true);
                    }else if(temp.charAt(i)==']'){
                        bracket.pop();
                        if(bracket.isEmpty()){
                            ret.add(temp.substring(0,i+1));
                            temp.replace(0,i+1,"");
                            break;
                        }
                    }
                }
            }
            //小括号包含
            else if(temp.charAt(0)=='('){
                for(int i=0;i<temp.length();i++){
                    if(temp.charAt(i)=='('){
                        bracket.push(true);
                    }else if(temp.charAt(i)==')'){
                        bracket.pop();
                        if(bracket.isEmpty()){
                            ret.add(temp.substring(0,i+1));
                            temp.replace(0,i+1,"");
                            break;
                        }
                    }
                }
            }
            //操作或操作数
            else {
                endIndex = temp.indexOf(" ");
                if(endIndex==-1){
                    ret.add(temp.substring(0));
                    break;
                }
                else ret.add(temp.substring(0,endIndex));
                temp.replace(0,endIndex+1,"");
            }
        }
        return ret;
    }
}
